/**
 * Package:com.afteryuan.server.hanlder.core;
 * $Id$
 * Copyright(c) 2001-2005 www.afteryuan.com
 */
package com.afteryuan.server.handler.core;

import com.afteryuan.server.ConnectSession;
import com.afteryuan.server.command.down.core.ExceptionDown;
import com.afteryuan.server.command.down.core.MoveAvatarDown;
import com.afteryuan.server.command.model.Avatar;
import com.afteryuan.server.command.model.Pane;
import com.afteryuan.server.command.up.CommandUp;
import com.afteryuan.server.command.up.core.RoadPathUp;
import com.afteryuan.server.data.Room;
import com.afteryuan.server.data.Sprite;
import com.afteryuan.server.data.SpritePool;
import com.afteryuan.server.handler.Handler;
import com.afteryuan.server.service.SpriteService;
import com.afteryuan.server.support.MovingSupport;
import com.afteryuan.server.support.Point;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * PathHandler 处理路径请求
 * <p/>
 * 处理步骤:
 * 1.判断sprite是否存在,如果不存在,则返回命令失败
 * 2.判断客户端上传的起点坐标是否合理,如果不合理,发送要求客户端更新状态的指令
 * 3.将Sprite加入正在移动的队列
 * 4.寻找路径,生成下行指令,并广播到当前场景
 * 5.更新Sprite状态
 * <p/>
 * <p/>
 * <p><a href="PathHandler.java.html"><i>View Source</i></a></p>
 *
 * @author <a href="mailto:afteryuan@afteryuan.com">$Author$</a>
 * @version $Revision$
 */
public class PathHandler implements Handler {
    /**
     * 客户端起点和服务器当前坐标之间的容忍度,当x,y轴之间的误差都小于此容忍度时,才采用客户端起点作为当前起点
     */
    public static final int tolerance = 1;

    private static Log log = LogFactory.getLog(PathHandler.class);
    private SpritePool spritePool;
    private SpriteService spriteService;
    private MovingSupport movingSupport;

    public void setMovingSupport(MovingSupport movingSupport) {
        this.movingSupport = movingSupport;
    }

    public void setSpritePool(SpritePool spritePool) {
        this.spritePool = spritePool;
    }

    public void setSpriteService(SpriteService spriteService) {
        this.spriteService = spriteService;
    }

    /**
     * 处理路径请求
     *
     * @param session 用户session
     * @param command 上行命令
     */
    public void process(ConnectSession session, CommandUp command) {
        RoadPathUp cmd = (RoadPathUp) command;
        Room room = new Room(cmd.sceneId, cmd.sceneInstanceId);
        Sprite sprite = spritePool.get(room, cmd.sender);
        //判断sprite是否存在,如果不存在,则返回命令失败
        if (sprite == null) {
            log.error("User " + cmd.sender + " is not in room " + cmd.sceneId + "->" + cmd.sceneInstanceId + ",command has been ignored。");
            session.write(new ExceptionDown(ExceptionDown.SENDER_NOT_EXIST));
            return;
        }

        //判断客户端上传的起点坐标是否合理,如果不合理,将以服务器为标准
        //todo 第一次的时候服务器没有保留当前位置,应该取其出生点
//        if (!isSamePoint(sprite.getCx(), sprite.getCy(), cmd.startX, cmd.startY)) {
//            cmd.startX = sprite.getCx();
//            cmd.startY = sprite.getCy();
//        }
        int sx = cmd.startX;
        int sy = cmd.startY;
        int tx = cmd.targetX;
        int ty = cmd.targetY;

        //将Sprite加入正在移动的队列
        spritePool.addToMoving(sprite);

        //寻找路径,生成下行指令
        MoveAvatarDown cmdDown = new MoveAvatarDown();
        Point begin = new Point(sx, sy);
        Point target = new Point(tx, ty);
//        Pane[] panes = movingSupport.movingPathArray(cmd.sceneId, begin, target);
        Pane[] panes = null;
        if(cmd.sender.indexOf("g")>=0)
        	panes = cmd.panes;
        else
        	panes = movingSupport.movingPathArray(cmd.sceneId, begin, target);
        cmdDown.avatar = new Avatar();
        cmdDown.avatar.delayTime = sprite.getDelay();
        cmdDown.avatar.listPane = panes;
        cmdDown.avatar.startX = sx;
        cmdDown.avatar.startY = sy;
        cmdDown.avatar.speed = cmd.speed;
        cmdDown.avatar.avatarId = cmd.sender;

        //todo 测试代码.主动延时
//        try {
//            Thread.sleep(1000);
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }

        //广播给场景中所有人
        spriteService.broadcast(room, cmdDown);

        //更新Sprite的状态
        sprite.setDx(tx);
        sprite.setDy(ty);
        sprite.setCx(sx);
        sprite.setCy(sy);
        sprite.setDelay(cmd.delay);
        sprite.setSpeed(cmd.speed);
        sprite.setPanes(panes);
    }

    private boolean isSamePoint(Integer cx, Integer cy, Integer startX, Integer startY) {
        return Math.abs(cx - startX) <= tolerance && Math.abs(cy - startY) <= tolerance;
    }

}